#ifndef TB_METSTYPE_reflection_REGISTER_HPP__
#define TB_METSTYPE_reflection_REGISTER_HPP__

template <class T> struct reflectionRegister;

#define DECLARE_reflection(THISTYPE, SUPERTYPE) \
public: \
	typedef THISTYPE self; \
	typedef SUPERTYPE super; \
	friend struct reflectionRegister<self>;	\
	static const TCHAR* ClassName(); \
  static uint32 ClassTypeId(); \
  virtual uint32 TypeId() const; \
  static const TB_NAMESPACE::reflection::Function* GetClassFunction(const TCHAR* funcName); \
  static const TB_NAMESPACE::reflection::Property* GetClassProperty(const TCHAR* propName); \
  static void Bind(void* l); \
  static int LuaNewProc(void* l); \
  static int LuaGetProc(void* l); \
  static int LuaSetProc(void* l); \
  static TB_NAMESPACE::shared_ptr<THISTYPE> Make();

#define TB_IMPL_reflection(THISTYPE) \
const TCHAR* THISTYPE::ClassName() { \
    static const TCHAR* className = _T(#THISTYPE); \
    return className; \
}	\
uint32 THISTYPE::ClassTypeId() { \
  static const uint32 typeId = \
  TB_NAMESPACE::reflection::RegisterType(new TB_NAMESPACE::reflection::DefaultAllocator<self>(), _T(#THISTYPE), TB_NAMESPACE::GetVariantTypeId<super>()); \
  return typeId; \
} \
uint32 THISTYPE::TypeId() const { \
  return self::ClassTypeId(); \
} \
void THISTYPE::Bind(void* l) { \
  TB_NAMESPACE::lua::NewClassMetatable(l, THISTYPE::ClassName(), (TB_NAMESPACE::lua::LuaFunctionT)&THISTYPE::LuaNewProc, \
    (TB_NAMESPACE::lua::LuaFunctionT)&THISTYPE::LuaGetProc, (TB_NAMESPACE::lua::LuaFunctionT)&THISTYPE::LuaSetProc); \
} \
const TB_NAMESPACE::reflection::Function* THISTYPE::GetClassFunction(const TCHAR* funcName) { \
  const TB_NAMESPACE::reflection::ConstFunctionsType funs = TB_NAMESPACE::reflection::GetFunctions(THISTYPE::ClassTypeId()); \
  for (TB_NAMESPACE::reflection::ConstFunctionsType::const_iterator it = funs.begin(); \
    it != funs.end(); \
    ++it) { \
    if ((*it)->name == funcName) { \
      return (*it); \
    } \
  } \
  return nullptr; \
} \
const TB_NAMESPACE::reflection::Property* THISTYPE::GetClassProperty(const TCHAR* propName) { \
  const TB_NAMESPACE::reflection::ConstPropertiesType props = TB_NAMESPACE::reflection::GetProperties(THISTYPE::ClassTypeId()); \
  for (TB_NAMESPACE::reflection::ConstPropertiesType::const_iterator it = props.begin(); \
    it != props.end(); \
    ++it) { \
    if ((*it)->name == propName) { \
      return (*it); \
    } \
  } \
  return nullptr; \
} \
int THISTYPE::LuaGetProc(void* l) { \
  return TB_NAMESPACE::lua::ImplementGetProc(l, (TB_NAMESPACE::lua::GetClassFunctionT)&THISTYPE::GetClassFunction, \
    (TB_NAMESPACE::lua::GetClassPropertyT)&THISTYPE::GetClassProperty); \
} \
int THISTYPE::LuaSetProc(void* l) { \
return TB_NAMESPACE::lua::ImplementSetProc(l, (TB_NAMESPACE::lua::GetClassFunctionT)&THISTYPE::GetClassFunction, \
    (TB_NAMESPACE::lua::GetClassPropertyT)&self::GetClassProperty); \
} \
TB_NAMESPACE::shared_ptr<THISTYPE> THISTYPE::Make() { \
  return TB_NAMESPACE::shared_ptr<THISTYPE>(reinterpret_cast<THISTYPE*>(\
    TB_NAMESPACE::reflection::ConstructType(THISTYPE::ClassTypeId(), false).Detach())); \
} \
int THISTYPE::LuaNewProc(void* l) { \
    return TB_NAMESPACE::lua::ImplementNewProc(l, THISTYPE::ClassName(), \
      TB_NAMESPACE::reflection::ConstructType(THISTYPE::ClassTypeId(), true)); \
}    

#define TB_REFLECTIONREGISTER_BEGIN(THISTYPE) \
template <> \
struct reflectionRegister<THISTYPE> { \
  typedef THISTYPE class_type; \
  reflectionRegister() { \
    using namespace TB_NAMESPACE; \
    using namespace TB_NAMESPACE::reflection; \
    uint32 typeId = GetVariantTypeId<class_type>();	\
    RegisterBegin(typeId); \
		RegisterTypeName(typeId, _T(#THISTYPE));

#define REGISTER_BEGIN(THISTYPE) \
TB_IMPL_reflection(THISTYPE) \
TB_REFLECTIONREGISTER_BEGIN(THISTYPE) \
    RegisterBindingProc((BindingProcType)&THISTYPE::Bind);

#define REGISTER_EXTERNAL_BEGIN(THISTYPE) \
TB_REFLECTIONREGISTER_BEGIN(THISTYPE) \

#define REGISTER_NAMESPACE(NSPACE) \
		RegisterNamespace(typeId, _T(NSPACE));				

#define REGISTER_PARENT(PARENT) \
		RegisterParent(typeId, GetVariantTypeId<PARENT>());

#define REGISTER_FIELD(FIELD, PNAME) \
    RegisterProperty(typeId, \
      MakePropertyField<class_type>(&class_type::FIELD, typeId, _T(#FIELD), _T(PNAME)));

#define REGISTER_FIELD2(NAME, FIELD, GETTER, SETTER, PNAME)	\
		RegisterProperty(typeId, \
			MakePropertyFieldAndProp<class_type, class_type::Data> \
			(&class_type::data_, &class_type::Data::FIELD, &class_type::GETTER, \
			&class_type::SETTER, typeId, _T(#NAME), _T(PNAME)));

#define REGISTER_PROPERTY(PROPERTY, PNAME)																\
    RegisterProperty(typeId,																							\
      MakePropertyProp<class_type>(&class_type::Get##PROPERTY, 						\
			&class_type::Set##PROPERTY, typeId, _T(#PROPERTY), _T(PNAME)));

#define REGISTER_PROPERTY2(GETTER, SETTER, NAME, PNAME) 				\
    RegisterProperty(typeId,																		\
      MakePropertyProp<class_type>(&class_type::GETTER, 				\
			&class_type::SETTER, typeId, _T(#NAME), _T(PNAME)));

#define REGISTER_FUNCTION(FUNCTION, ...)				\
    RegisterMethod(typeId,											\
      MakeFunction(&class_type::FUNCTION, __VA_ARGS__));

#define REGISTER_END() 													\
    RegisterEnd(typeId); \
  }																							\
  static void Magic() { 												\
    TB_NAMESPACE::SingletonActivator< reflectionRegister<class_type> >::Activate(); \
  } \
};

#define REGISTER_GlOBAL_FUNCTION(NSPACE, FUNCTION, ...)			\
   TB_NAMESPACE::reflection::RegisterGlobalFunction(NSPACE,	\
      TB_NAMESPACE::reflection::MakeFunction(FUNCTION, _T(#FUNCTION), ##__VA_ARGS__));

#define REGISTER_reflection(TYPE, NAME)						\
template <> 																		\
struct reflectionRegister<TYPE> { 								\
  reflectionRegister() { 													\
    (void)GetVariantTypeId<TYPE>(); 								\
  } 																						\
  static void Magic() { 												\
    TB_NAMESPACE::SingletonActivator< reflectionRegister<type> >::Activate(); \
  } 																						\
};

#define REGISTER_CONTAINER_IMPL(TYPE, FIRSTTYPE, SECONDTYPE) 	\
template <> 																									\
struct reflectionRegister<TYPE> { 															\
  reflectionRegister() { 																				\
    uint32 typeId = TB_NAMESPACE::GetVariantTypeId<TYPE>(); 		\
		TB_NAMESPACE::reflection::RegisterTypeName(typeId, _T(#TYPE)); \
    TB_NAMESPACE::reflection::RegisterContainer(typeId,       \
    TB_NAMESPACE::GetVariantTypeId<FIRSTTYPE>(),               \
    TB_NAMESPACE::GetVariantTypeId<SECONDTYPE>(),              \
    TB_NAMESPACE::reflection::MakeContainerIterator<TYPE>()); \
  } 																													\
  static void Magic() { 																			\
    TB_NAMESPACE::SingletonActivator< reflectionRegister<TYPE> >::Activate(); \
  } 																													\
};

#define REGISTER_PAIR_IMPL(FIRSTTYPE, SECONDTYPE) 						\
template <> 																									\
struct reflectionRegister<_STD pair<FIRSTTYPE, SECONDTYPE> > { 	\
	typedef _STD pair<FIRSTTYPE, SECONDTYPE> pair_type;					\
  reflectionRegister() { 																				\
    uint32 typeId = TB_NAMESPACE::GetVariantTypeId<pair_type>(); 		\
		TB_NAMESPACE::reflection::RegisterTypeName(typeId, typeid(pair_type).name()); \
    TB_NAMESPACE::reflection::RegisterPair(typeId,						\
    TB_NAMESPACE::GetVariantTypeId<FIRSTTYPE>(),               \
    TB_NAMESPACE::GetVariantTypeId<SECONDTYPE>());							\
  } 																													\
  static void Magic() { 																			\
    TB_NAMESPACE::SingletonActivator< reflectionRegister<pair_type> >::Activate(); \
  } 																													\
};

#define REGISTER_PAIR(FIRSTTYPE, SECONDTYPE) \
	REGISTER_PAIR_IMPL(FIRSTTYPE, SECONDTYPE)

#define REGISTER_CONTAINER(TYPE, ELEMTYPE) \
  REGISTER_CONTAINER_IMPL(TYPE, ELEMTYPE, TB_NAMESPACE::NoneType)

#define REGISTER_MAP_CONTAINER(TYPE, KEYTYPE, VALUETYPE) \
  REGISTER_CONTAINER_IMPL(TYPE, KEYTYPE, VALUETYPE)

#define REGISTER_TRIVAL_ARRAY(TYPE, SIZE) \
  REGISTER_CONTAINER(TYPE[SIZE], TYPE)

#define REGISTER_STD_VECTOR(ELEMTYPE) \
  REGISTER_CONTAINER(std::vector<ELEMTYPE>, ELEMTYPE)

#define REGISTER_STD_LIST(ELEMTYPE) \
  REGISTER_CONTAINER(std::list<ELEMTYPE>, ELEMTYPE)

#endif // TB_METSTYPE_reflection_REGISTER_HPP__
